import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
import { isFunction } from "../is";

import { RequestOptions, Result, CreaterAxiosOptions } from "./types";

export class LAxios {
  private axiosInstance: AxiosInstance;
  private options: CreaterAxiosOptions;

  constructor(options: CreaterAxiosOptions) {
    this.options = options;
    this.axiosInstance = axios.create(options);
    this.setupInterceptors();
  }

  private createAxios(config: CreaterAxiosOptions) {
    this.axiosInstance = axios.create(config);
  }

  private getTransform() {
    const { transform } = this.options;
    return transform;
  }

  getAxios() {
    return this.axiosInstance;
  }

  setAxiosConfig(config: CreaterAxiosOptions) {
    if (!this.axiosInstance) {
      return;
    }
    this.createAxios(config);
  }

  /**
   *配置拦截器
   * @returns void
   */
  private setupInterceptors() {
    const transform = this.getTransform();
    if (!transform) {
      return;
    }
    const {
      requestInterceptors,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform;

    this.axiosInstance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        if (requestInterceptors && isFunction(requestInterceptors)) {
          config = requestInterceptors(config);
        }
        return config;
      },
      undefined
    );

    this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
      if (responseInterceptors && isFunction(responseInterceptors)) {
        res = responseInterceptors(res);
      }
      return res;
    }, undefined);

    responseInterceptorsCatch &&
      isFunction(responseInterceptorsCatch) &&
      this.axiosInstance.interceptors.response.use(
        undefined,
        responseInterceptorsCatch
      );
  }

  requst<T = any>(
    config: AxiosRequestConfig,
    options?: RequestOptions
  ): Promise<T> {
    let conf: AxiosRequestConfig = config;
    const { requestOptions } = this.options;
    const opt: RequestOptions = Object.assign({}, requestOptions, options);

    const transform = this.getTransform();
    const { beforeRequestHook } = transform || {};
    if (beforeRequestHook && isFunction(beforeRequestHook)) {
      conf = beforeRequestHook(conf, opt);
    }
    return new Promise((resolve) => {
      this.axiosInstance
        .request<any, AxiosResponse<Result>>(conf)
        .then((res: any) => {
          return resolve(res);
        });
    });
  }
}
